home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************************\
- * PC2.c *
- * Copyright (C) by Stangl Roman, 1993, 1994 *
- * This Code may be freely distributed, provided the Copyright isn't *
- * removed. *
- * *
- * Pc2Hook.c Hook the input queue to filter certain messages. *
- * *
- \***********************************************************************/
-
- static char RCSID[]="@(#) $Header: Pc2Hook.c Version 1.70 06,1994 $ (LBL)";
-
- #define _FILE_ "PC/2 - PC2Hook.c V1.70"
-
- #include "PC2.h" /* User include files */
- #include "Error.h"
-
- /*--------------------------------------------------------------------------------------*\
- * The following functions are exported in PC2Hook.def *
- \*--------------------------------------------------------------------------------------*/
- void EXPENTRY PC2DLL_SetParameters(void);
- BOOL EXPENTRY PC2DLL_Hook(HAB hab, PQMSG pqmsg, ULONG option);
-
- /*--------------------------------------------------------------------------------------*\
- * The following datastructures are exported in PC2Hook.def *
- \*--------------------------------------------------------------------------------------*/
- HOOKPARAMETERS HookParameters; /* Central control structure for PC/2 */
- KEYDATA KeyData[KEYDATACOUNT]={ /* Hotkeys defined within PC/2 */
- {KC_CTRL, '0', FALSE, NULL}, {KC_CTRL, '1', FALSE, NULL}, {KC_CTRL, '2', FALSE, NULL},
- {KC_CTRL, '3', FALSE, NULL}, {KC_CTRL, '4', FALSE, NULL}, {KC_CTRL, '5', FALSE, NULL},
- {KC_CTRL, '6', FALSE, NULL}, {KC_CTRL, '7', FALSE, NULL}, {KC_CTRL, '8', FALSE, NULL},
- {KC_CTRL, '9', FALSE, NULL},
- {KC_CTRL, 'A', FALSE, NULL}, {KC_CTRL, 'B', FALSE, NULL}, {KC_CTRL, 'C', FALSE, NULL},
- {KC_CTRL, 'D', FALSE, NULL}, {KC_CTRL, 'E', FALSE, NULL}, {KC_CTRL, 'F', FALSE, NULL},
- {KC_CTRL, 'G', FALSE, NULL}, {KC_CTRL, 'H', FALSE, NULL}, {KC_CTRL, 'I', FALSE, NULL},
- {KC_CTRL, 'J', FALSE, NULL}, {KC_CTRL, 'K', FALSE, NULL}, {KC_CTRL, 'L', FALSE, NULL},
- {KC_CTRL, 'M', FALSE, NULL}, {KC_CTRL, 'N', FALSE, NULL}, {KC_CTRL, 'O', FALSE, NULL},
- {KC_CTRL, 'P', FALSE, NULL}, {KC_CTRL, 'Q', FALSE, NULL}, {KC_CTRL, 'R', FALSE, NULL},
- {KC_CTRL, 'S', FALSE, NULL}, {KC_CTRL, 'T', FALSE, NULL}, {KC_CTRL, 'U', FALSE, NULL},
- {KC_CTRL, 'V', FALSE, NULL}, {KC_CTRL, 'W', FALSE, NULL}, {KC_CTRL, 'X', FALSE, NULL},
- {KC_CTRL, 'Y', FALSE, NULL}, {KC_CTRL, 'Z', FALSE, NULL},
- {KC_ALT, '0', FALSE, NULL}, {KC_ALT, '1', FALSE, NULL}, {KC_ALT, '2', FALSE, NULL},
- {KC_ALT, '3', FALSE, NULL}, {KC_ALT, '4', FALSE, NULL}, {KC_ALT, '5', FALSE, NULL},
- {KC_ALT, '6', FALSE, NULL}, {KC_ALT, '7', FALSE, NULL}, {KC_ALT, '8', FALSE, NULL},
- {KC_ALT, '9', FALSE, NULL},
- {KC_ALT, 'A', FALSE, NULL}, {KC_ALT, 'B', FALSE, NULL}, {KC_ALT, 'C', FALSE, NULL},
- {KC_ALT, 'D', FALSE, NULL}, {KC_ALT, 'E', FALSE, NULL}, {KC_ALT, 'F', FALSE, NULL},
- {KC_ALT, 'G', FALSE, NULL}, {KC_ALT, 'H', FALSE, NULL}, {KC_ALT, 'I', FALSE, NULL},
- {KC_ALT, 'J', FALSE, NULL}, {KC_ALT, 'K', FALSE, NULL}, {KC_ALT, 'L', FALSE, NULL},
- {KC_ALT, 'M', FALSE, NULL}, {KC_ALT, 'N', FALSE, NULL}, {KC_ALT, 'O', FALSE, NULL},
- {KC_ALT, 'P', FALSE, NULL}, {KC_ALT, 'Q', FALSE, NULL}, {KC_ALT, 'R', FALSE, NULL},
- {KC_ALT, 'S', FALSE, NULL}, {KC_ALT, 'T', FALSE, NULL}, {KC_ALT, 'U', FALSE, NULL},
- {KC_ALT, 'V', FALSE, NULL}, {KC_ALT, 'W', FALSE, NULL}, {KC_ALT, 'X', FALSE, NULL},
- {KC_ALT, 'Y', FALSE, NULL}, {KC_ALT, 'Z', FALSE, NULL} };
-
- /*--------------------------------------------------------------------------------------*\
- * The following datastructures are local for in PC2Hook.dll *
- \*--------------------------------------------------------------------------------------*/
- ULONG ulMoveFlag; /* xxxxxxxx (<-Bit 0)
- | Move all windows in x direction
- | Move in -x direction
- | Move in y direction
- | Move in -y direction
- | Click required to move */
- LONG SlidingXFactor; /* Slide in x direction in pixels */
- LONG SlidingYFactor; /* Slide in y direction in pixels */
- /* Hotkeys defined for PS/2 */
- QUERYRECFROMRECT QueryRect; /* Rectangle to query underlaying containers */
-
- /*--------------------------------------------------------------------------------------*\
- * This procedure saves the data used in the PC/2 main procedure for use within the *
- * DLL. *
- * Req: *
- * none *
- * Returns: *
- * none *
- \*--------------------------------------------------------------------------------------*/
- void EXPENTRY PC2DLL_SetParameters(void)
- {
- /* Initialize to query the topmost underlaying
- container, that is partially hit by a rectangle
- around the pointer */
- QueryRect.cb=sizeof(QUERYRECFROMRECT);
- QueryRect.fsSearch=CMA_PARTIAL | CMA_ZORDER;
- }
-
- /*--------------------------------------------------------------------------------------*\
- * This procedure implements the hook of the input queue. . *
- * Req: *
- * PQMSG ......... Pointer to system QMSG structure *
- * Returns: *
- * FALSE ......... OS/2 should process QMSG in the normal way *
- \*--------------------------------------------------------------------------------------*/
- BOOL EXPENTRY PC2DLL_Hook(HAB hab, PQMSG pqmsg, ULONG option)
- {
- static ULONG ulButtonDown=0; /* Last button down on PM, either WM_BUTTON1DOWN
- or WM_BUTTON2DOWN or 0 if pointer is not over
- PM */
-
- /* Return if mouse is captured */
- if(WinQueryCapture(HWND_DESKTOP)!=NULLHANDLE) return(FALSE);
- /* *\
- * Here we catch mouse button clicks on the PM to be able to send PC/2 a message when *
- * it should display the window list, because the window list is only displayed if the *
- * mouse is clicked on the WPS (not displaying the window list on PM). *
- * The window list is invoked (like on the WPS) when one mouse button is down, and the *
- * other mouse button is pressed down too, but only if we are over PM. *
- \* */
- /* If one button is down and none was down before
- save it because window list requires second button
- down too */
- if((pqmsg->msg==WM_BUTTON1DOWN) && (ulButtonDown!=WM_BUTTON2DOWN))
- ulButtonDown=WM_BUTTON1DOWN;
- if((pqmsg->msg==WM_BUTTON2DOWN) && (ulButtonDown!=WM_BUTTON1DOWN))
- ulButtonDown=WM_BUTTON2DOWN;
- /* If one button goes up ignore previous buttons down */
- if((pqmsg->msg==WM_BUTTON1UP) || (pqmsg->msg==WM_BUTTON2UP)) ulButtonDown=0;
- if((pqmsg->hwnd!=HookParameters.hwndDesktop) && (pqmsg->msg==WM_MOUSEMOVE))
- ulButtonDown=0; /* If the mouse is not over PM reset window list flag */
- /* If the user holds down both mouse buttons on PM display Window List */
- if((pqmsg->msg==WM_BUTTON1DOWN) && (ulButtonDown==WM_BUTTON2DOWN))
- {
- ulButtonDown=0;
- WinSendMsg(HookParameters.hwndPC2, WM_WINDOWLIST, MPFROMLONG(pqmsg->mp1), NULL);
- return(TRUE); /* Don't pass this message to next hook in chain. */
- }
- if((pqmsg->msg==WM_BUTTON2DOWN) && (ulButtonDown==WM_BUTTON1DOWN))
- {
- ulButtonDown=0;
- WinSendMsg(HookParameters.hwndPC2, WM_WINDOWLIST, MPFROMLONG(pqmsg->mp1), NULL);
- return(TRUE); /* Don't pass this message to next hook in chain. */
- }
- /* *\
- * Here we catch all WM_BUTTON2DOWN messages. If it was clicked on any window's *
- * titlebar then set this window to the bottom of the Desktop. WM_BUTTON2DOWN is used *
- * to prevent the moving frame to be drawn (which is the default action of a *
- * WM_BUTTON2DOWN message on a window's titlebar. *
- * This function using WM_BUTTON2DBLCLK was first implemented by Robert Mahoney's *
- * utiltiy WinBack, modified by Rolf Knebel to add this functionality to PC/2. However *
- * using a doubleclick with mouse button 2 has the drawback that the window is brought *
- * into the foreground first (because clicking on the titlebar activates a window) and *
- * then moved to the bottom (causing many unnecessary drawings). *
- \* */
- if((pqmsg->msg==WM_BUTTON2DOWN) && (HookParameters.ulStatusFlag & BUTTON2ZORDER))
- {
- HWND hwndApplicationParent=WinQueryWindow(pqmsg->hwnd, QW_PARENT);
-
- /* If we click on a titlebar the current window handle
- equals the parent's titlebar window handle */
- if(pqmsg->hwnd==WinWindowFromID(hwndApplicationParent, FID_TITLEBAR))
- { /* Set it to the bottom of all windows */
- WinSetWindowPos(hwndApplicationParent, HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER|SWP_DEACTIVATE);
- return(TRUE); /* Don't pass this message to next hook in chain. */
- }
- }
- /* *\
- * Here we catch all WM_CHAR messages filtering them for hotkeys. Found hotkeys are *
- * sent to PC/2. *
- \* */
- if(pqmsg->msg == WM_CHAR)
- {
- USHORT usFlags=SHORT1FROMMP(pqmsg->mp1)&(KC_CTRL|KC_ALT);
- USHORT usCh=SHORT1FROMMP(pqmsg->mp2);
-
- /* Convert any non numeric character to uppercase */
- if((usCh>(USHORT)'9') || (usCh<(USHORT)'0')) usCh &= ~0x20;
- if((usFlags==KC_CTRL) || (usFlags==KC_ALT))
- {
- KEYDATA *pKeyData=KeyData;
- ULONG ulKeyDataIndex=0;
- /* Now try to find the key */
- for( ;ulKeyDataIndex<=KEYDATACOUNT; ulKeyDataIndex++, pKeyData++)
- if((pKeyData->usFlags==usFlags) && (pKeyData->usCh==usCh))
- {
- if(pKeyData->bUsed==TRUE)
- {
- WinPostMsg(HookParameters.hwndPC2, WM_HOTKEY,
- MPFROM2SHORT(usFlags, usCh), MPFROMLONG(ulKeyDataIndex));
- return(TRUE); /* Don't pass this message to next hook in chain. */
- }
- else break; /* If our key is not used we don't need any
- further search */
- }
- }
- }
- /* *\
- * Here we catch mouse button 1 clicks, either the move the Desktop or to display the *
- * Popup-Menu. *
- \* */
- while(pqmsg->msg==HookParameters.ulClickFlag)
- {
- /* *\
- * If the user clicked on at least one of the surrounding rows or columns of the *
- * display, we shift the physical Desktop on the virtual Desktop. The flag MOVED4CLICK *
- * is set, if the user click on the display borders. *
- \* */
- if(ulMoveFlag & MOVED4CLICK)
- {
- WinSendMsg(HookParameters.hwndPC2, WM_MOVEREQUEST,
- MPFROM2SHORT(pqmsg->ptl.x, pqmsg->ptl.y), MPFROMLONG(ulMoveFlag));
- ulMoveFlag&=~MOVED4CLICK; /* Reset flag, because only a move before
- a click may set it */
- return(TRUE); /* Don't pass this message to next hook in chain. */
- }
- /* *\
- * If the user clicked on the WPS or PM window, send PC/2 a message to display the *
- * Popup-Menu. *
- \* */
- if(pqmsg->hwnd==HookParameters.hwndWPS)
- { /* The user clicked on WPS "Desktop" window.
- We construct a small rectangle around the
- current position of the pointer */
- QueryRect.rect.xLeft=pqmsg->ptl.x;
- QueryRect.rect.xRight=pqmsg->ptl.x+1;
- QueryRect.rect.yBottom=pqmsg->ptl.y;
- QueryRect.rect.yTop=pqmsg->ptl.y+1;
- if(WinSendMsg(HookParameters.hwndWPS, CM_QUERYRECORDFROMRECT,
- MPFROMLONG(CMA_FIRST), &QueryRect)==NULL)
- /* If no container is under the rectangle of the
- mouse pointer, we can display our Popup-Menu.
- The type of container is unknown, but because
- we test only on the WPS, they should usually
- be the icons (but not the minimized programs,
- which are windows with a different window handle). */
- /* Pass the pointer position in coordinates relative
- to the window and the handle of that window.
- The coordinates must be translated from that
- window to the display */
- {
- WinSendMsg(HookParameters.hwndPC2, WM_POPUPMENU,
- MPFROMLONG(pqmsg->mp1), MPFROMHWND(pqmsg->hwnd));
- return(TRUE); /* Don't pass this message to next hook in chain. */
- }
- break; /* If clicked on an container, pass message to WPS */
- }
- if(pqmsg->hwnd==HookParameters.hwndDesktop)
- { /* The user clicked on the PM "Desktop" window.
- If the WPS isn't installed we only get the PM
- windows. We can now display our Popup-Menu.
- Pass the pointer position in coordinates relative
- to the window and the handle of that window.
- The coordinates must be translated from that
- window to the display */
- WinSendMsg(HookParameters.hwndPC2, WM_POPUPMENU,
- MPFROMLONG(pqmsg->mp1), MPFROMHWND(pqmsg->hwnd));
- return(TRUE); /* Don't pass this message to next hook in chain. */
- }
- break; /* Break out of while loop */
- }
- /* *\
- * If enabled, here we catch all mouse movements, to set the window under the mouse *
- * pointer as the active one, if it isn't currently active or the window list or *
- * optionally the Desktop window. *
- \* */
- while((pqmsg->msg==WM_MOUSEMOVE) && (HookParameters.ulStatusFlag & SLIDINGFOCUS))
- { /* If enabled, use sliding focus to activate window
- under the mouse pointer (with some exceptions).
- Caution! Menus have a class WC_MENU, but their
- parent is not the frame window WC_FRAME but the
- Desktop itself. */
- static UCHAR ucClassname[7]; /* Window class f.e. #1 for WC_FRAME */
- static UCHAR ucWindowText[33]; /* Window name f.e. OS/2 2.0 Desktop */
- static HWND hwndActive; /* Window handle of active frame class window on Desktop */
- static HWND hwndApplication; /* Window handle of application under mouse pointer */
- /* Window handle of applications parent window */
- static HWND hwndApplicationParent;
-
- /* Query the currently active window, where HWND_DESKTOP
- is the parent window. It will be a WC_FRAME class
- window */
- hwndActive=WinQueryActiveWindow(HWND_DESKTOP);
- WinQueryWindowText(hwndActive, sizeof(ucWindowText), ucWindowText);
- /* Don't switch away from the WC_FRAME class tasklist */
- if(!strcmp(ucWindowText, HookParameters.ucWindowListName)) break;
- hwndApplication=pqmsg->hwnd; /* Get message target window */
- if((hwndApplication==HookParameters.hwndDesktop) || (hwndApplication==HookParameters.hwndWPS))
- break; /* If the window under the mouse pointer is one of the
- Desktops, don't do any changes */
- /* Get parent window of current window */
- hwndApplicationParent=WinQueryWindow(hwndApplication, QW_PARENT);
- while(hwndApplicationParent!=HookParameters.hwndDesktop)
- { /* Loop until we get the Desktop window handle. The
- previous child window of the Desktop is then the
- WC_FRAME class window of the point under the mouse
- pointer which is not the Desktop. */
- hwndApplication=hwndApplicationParent;
- hwndApplicationParent=WinQueryWindow(hwndApplication, QW_PARENT);
- }
- /* Query the class of the frame window of the
- designated target of WM_MOUSEMOVE */
- WinQueryClassName(hwndApplication, sizeof(ucClassname), ucClassname);
- /* Query the frame window name of the designated
- target of WM_MOUSEMOVE */
- WinQueryWindowText(hwndApplication, sizeof(ucWindowText), ucWindowText);
- while(TRUE)
- { /* Sort with expected descending probability, to avoid
- unnecessary cpu load */
- /* Don't switch if previous windows equals current one */
- if(hwndActive==hwndApplication) break;
- /* Only switch to WC_FRAME class windows */
- if(strcmp(ucClassname, "#1")) break;
- /* Don't switch to the WC_FRAME class window of PC/2 */
- if(strstr(ucWindowText, "PC/2")) break;
- if(HookParameters.ulStatusFlag & PRESERVEZORDER)
- { /* Change focus, but preserve Z-order */
- /* Don't send WM_ACTIVATE to window with new focus */
- WinFocusChange(HWND_DESKTOP, pqmsg->hwnd, FC_NOSETACTIVE);
- /* Activate new window */
- WinPostMsg(hwndApplication, WM_ACTIVATE, MPFROMSHORT(TRUE), MPFROMHWND(pqmsg->hwnd));
- }
- else /* Now switch to the new frame window, causing
- a new Z-order. It will generate all messages
- of deactivating old and activating the
- new window. */
- WinFocusChange(HWND_DESKTOP, pqmsg->hwnd, 0);
- return(TRUE); /* We changed the focus, don't pass this message to
- the next hook in the chain */
- }
- break; /* Exit loop now */
- }
- /* *\
- * If enabled, here we catch all mouse movements that are on the surrounding rows and *
- * columns of the physical Desktop, to adjust the position of the physical Desktop *
- * within the virtual Desktop. *
- \* */
- while((pqmsg->msg==WM_MOUSEMOVE) && (HookParameters.ulStatusFlag & VIRTUALDESKTOP))
- {
- ulMoveFlag=0;
- if(pqmsg->ptl.x<=0)
- { /* If we are on the left border of our physical
- Desktop, move all windows right as we shift
- it leftwards on the virtual Desktop */
- ulMoveFlag|=MOVEXR;
- /* If we're in the lower left corner, also move
- all windows up and shift downwards on the
- virtual Desktop */
- if(pqmsg->ptl.y<=HookParameters.LLHotBorder.y) ulMoveFlag|=MOVEYU;
- /* If we're in the upper left corner, also move
- all windows down and shift upwards on the
- virtual Desktop */
- if(pqmsg->ptl.y>=HookParameters.URHotBorder.y) ulMoveFlag|=MOVEYD;
- }
- if(pqmsg->ptl.x>=HookParameters.DesktopSize.x-1)
- { /* If we are on the right border of our physical
- Desktop, move all windows left as we shift
- it rightwards on the virtual Desktop */
- ulMoveFlag|=MOVEXL;
- if(pqmsg->ptl.y<=HookParameters.LLHotBorder.y) ulMoveFlag|=MOVEYU;
- if(pqmsg->ptl.y>=HookParameters.URHotBorder.y) ulMoveFlag|=MOVEYD;
- }
- if(pqmsg->ptl.y<=0)
- { /* If we are on the bottom border of our physical
- Desktop, move all windows up as we shift
- it downwards on the virtual Desktop */
- ulMoveFlag|=MOVEYU;
- if(pqmsg->ptl.x<=HookParameters.LLHotBorder.x) ulMoveFlag|=MOVEXR;
- if(pqmsg->ptl.x>=HookParameters.URHotBorder.x) ulMoveFlag|=MOVEXL;
- }
- if(pqmsg->ptl.y>=HookParameters.DesktopSize.y-1)
- { /* If we are on the top border of our physical
- Desktop, move all windows down as we shift
- it upwards on the virtual Desktop */
- ulMoveFlag|=MOVEYD;
- if(pqmsg->ptl.x<=HookParameters.LLHotBorder.x) ulMoveFlag|=MOVEXR;
- if(pqmsg->ptl.x>=HookParameters.URHotBorder.x) ulMoveFlag|=MOVEXL;
- }
- if(ulMoveFlag==0) break; /* If there is no window to move, don't do any
- further processing and exit loop. As no flags
- are set, the click loop will not find
- the necessity to move */
- ulMoveFlag|=MOVED4CLICK; /* We're now about to move, but if the user
- selected to click before move, we exit this
- loop with the flags set. The click loop
- will then use these flags */
- if(HookParameters.ulStatusFlag & CLICK2MOVE) break;
- WinPostMsg(HookParameters.hwndPC2, WM_MOVEREQUEST,
- MPFROM2SHORT(pqmsg->ptl.x, pqmsg->ptl.y), MPFROMLONG(ulMoveFlag));
- return(TRUE); /* Exit from loop */
- }
- return(FALSE); /* Process the message in the normal way */
- }
-